#include "gd32f30x.h"
#include "string.h"
#include "stdint.h"
#include "stdio.h"
#include "DevicesDelay.h"
#include "DevicesQueue.h"
#include "DevicesCAN.h"


void vCan0Init(void)
{
    can_parameter_struct can_parameter = {0};
    can_filter_parameter_struct can_filter = {0};

    /* enable CAN clock */
    rcu_periph_clock_enable(RCU_CAN0);
    rcu_periph_clock_enable(RCU_GPIOD);

    /* configure CAN0 GPIO */
    gpio_init(GPIOD, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
    /* 端口重映射 */
    gpio_pin_remap_config(GPIO_CAN0_FULL_REMAP, ENABLE);


    /* initialize CAN register */
    can_deinit(CAN0);

    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
    /* initialize CAN parameters */
    can_parameter.time_triggered = DISABLE;
    can_parameter.auto_bus_off_recovery = DISABLE;
    can_parameter.auto_wake_up = DISABLE;
    can_parameter.auto_retrans = DISABLE;
    can_parameter.rec_fifo_overwrite = ENABLE;
    can_parameter.trans_fifo_order = ENABLE;
    can_parameter.working_mode = CAN_NORMAL_MODE;
    /* 波特率：PCLK1 / can_parameter.prescaler / (1 + can_parameter.time_segment_1 + can_parameter.time_segment_2) */
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1 = CAN_BT_BS1_12TQ;
    can_parameter.time_segment_2 = CAN_BT_BS2_7TQ;
    can_parameter.prescaler = 12;
    /* initialize CAN */
    can_init(CAN0, &can_parameter);


    can_struct_para_init(CAN_INIT_STRUCT, &can_filter);
    /* initialize filter */
    can_filter.filter_fifo_number = CAN_FIFO0;
    can_filter.filter_enable = ENABLE;
    can_filter.filter_bits = CAN_FILTERBITS_32BIT;
    can_filter.filter_mode = CAN_FILTERMODE_MASK;

    can_filter.filter_number = 0;
    /* 全局地址 */
    can_filter.filter_mask_high = ((0xF00000 << 3) | 0x07) >> 16;
    can_filter.filter_mask_low  = ((0xF00000 << 3) | 0x07) & 0xFFFF;
    can_filter.filter_list_high = ((0xF00000 << 3) | CAN_FF_EXTENDED | CAN_FT_DATA) >> 16;
    can_filter.filter_list_low  = ((0xF00000 << 3) | CAN_FF_EXTENDED | CAN_FT_DATA) & 0xFFFF;
    can_filter_init(&can_filter);

    can_filter.filter_number = 1;
    /* 本机地址 */
    can_filter.filter_mask_high = ((0xFF00 << 3) | 0x07) >> 16;
    can_filter.filter_mask_low  = ((0xFF00 << 3) | 0x07) & 0xFFFF;
    can_filter.filter_list_high = ((0xF400 << 3) | CAN_FF_EXTENDED | CAN_FT_DATA) >> 16;
    can_filter.filter_list_low  = ((0xF400 << 3) | CAN_FF_EXTENDED | CAN_FT_DATA) & 0xFFFF;
    can_filter_init(&can_filter);

    can_filter.filter_number = 2;
    can_filter_init(&can_filter);


    /* configure CANx NVIC */
    nvic_irq_enable(CAN0_RX0_IRQn, 7, 0);
    /* enable can receive FIFOx not empty interrupt */
    can_interrupt_enable(CAN0, CAN_INT_RFNE0);
}

void vCan1Init(void)
{
    can_parameter_struct can_parameter = {0};
    can_filter_parameter_struct can_filter = {0};

    /* enable CAN clock */
    rcu_periph_clock_enable(RCU_CAN1);
    rcu_periph_clock_enable(RCU_GPIOB);

    /* configure CAN0 GPIO */
    gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    /* 端口重映射 */
    gpio_pin_remap_config(GPIO_CAN1_REMAP, ENABLE);


    /* initialize CAN register */
    can_deinit(CAN1);

    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
    /* initialize CAN parameters */
    can_parameter.time_triggered = DISABLE;
    can_parameter.auto_bus_off_recovery = DISABLE;
    can_parameter.auto_wake_up = DISABLE;
    can_parameter.auto_retrans = DISABLE;
    can_parameter.rec_fifo_overwrite = ENABLE;
    can_parameter.trans_fifo_order = ENABLE;
    can_parameter.working_mode = CAN_NORMAL_MODE;
    /* 波特率：PCLK1 / can_parameter.prescaler / (1 + can_parameter.time_segment_1 + can_parameter.time_segment_2) */
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1 = CAN_BT_BS1_5TQ;
    can_parameter.time_segment_2 = CAN_BT_BS2_4TQ;
    can_parameter.prescaler = 6;
    /* initialize CAN */
    can_init(CAN1, &can_parameter);


    can_struct_para_init(CAN_INIT_STRUCT, &can_filter);
    /* initialize filter */
    can_filter.filter_fifo_number = CAN_FIFO1;
    can_filter.filter_enable = ENABLE;
    can_filter.filter_bits = CAN_FILTERBITS_32BIT;
    can_filter.filter_mode = CAN_FILTERMODE_MASK;
    can_filter.filter_mask_high = 0x0000;
    can_filter.filter_mask_low = 0x00FF;
    can_filter.filter_list_low = CAN_FF_EXTENDED | CAN_FT_DATA | (3 << 3);
    can_filter.filter_number = 14;
    can_filter_init(&can_filter);


    /* configure CANx NVIC */
    nvic_irq_enable(CAN1_RX1_IRQn, 7, 0);
    /* enable can receive FIFOx not empty interrupt */
    can_interrupt_enable(CAN1, CAN_INT_RFNE1);
}

int8_t cCanxSendDatas(uint32_t can_periph, uint32_t uiID, void *pvDatas, int32_t iLength)
{
    can_trasnmit_message_struct transmit_message;
    uint8_t *pucDatas = pvDatas;
    int32_t iTimeOut;
    int8_t cError = 0;

    if(pvDatas == NULL)
        return 1;

    /* initialize transmit message */
    transmit_message.tx_sfid = 0;
    transmit_message.tx_efid = uiID;
    transmit_message.tx_ft = CAN_FT_DATA;
    transmit_message.tx_ff = CAN_FF_EXTENDED;

    while(iLength > 0)
    {
        /* 计算当前帧传输长度 */
        transmit_message.tx_dlen = (iLength > 8) ? 8 : iLength;

        memcpy(transmit_message.tx_data, pucDatas, transmit_message.tx_dlen);

        pucDatas += transmit_message.tx_dlen;
        iLength  -= transmit_message.tx_dlen;

        /* 发送数据 */
        for(iTimeOut = 1000; (can_message_transmit(can_periph, &transmit_message) == CAN_NOMAILBOX) && (iTimeOut > 0); --iTimeOut)
            vDelayUs(10);

        if(iTimeOut <= 0)
        {
            printf("cCanxSendDatas error.\r\n");
            cError = 2;
            break;
        }
    }

    return cError;
}

int8_t cCanxReceiveByte(uint32_t can_periph, uint8_t *pucByte)
{
    return cCanxReceiveDatas(can_periph, pucByte, 1);
}

int8_t cCanxReceiveDatas(uint32_t can_periph, void *pvDatas, int32_t iLength)
{
    QueueType *ptypeQueueHandle = NULL;

    if(iLength < 1)
        return 1;

    switch(can_periph)
    {
        case CAN0: ptypeQueueHandle = &g_TypeQueueCan0Read; break;
        case CAN1: ptypeQueueHandle = &g_TypeQueueCan1Read; break;

        default : printf("cCanxReceiveDatas channel error.\r\n"); return 2;
    }

    /* 判断队列内是否有足够的数据 */
    if(iQueueGetLengthOfOccupy(ptypeQueueHandle) < iLength)
        return 3;

    /* 从队列内获取数据 */
    if(enumQueuePopDatas(ptypeQueueHandle, pvDatas, iLength) != queueNormal)
        return 4;

    return 0;
}

int32_t iCanxReceiveAllDatas(uint32_t can_periph, void *pvDatas, int32_t iLengthLimit)
{
    QueueType *ptypeQueueHandle = NULL;
    int32_t iLength = 0;

    if((pvDatas == NULL) || (iLengthLimit < 1))
        return 0;

    switch(can_periph)
    {
        case CAN0: ptypeQueueHandle = &g_TypeQueueCan0Read; break;
        case CAN1: ptypeQueueHandle = &g_TypeQueueCan1Read; break;

        default : printf("iCanxReceiveAllDatas channel error.\r\n"); return 0;
    }

    /* 读取队列内有效数据的长度 */
    if((iLength = iQueueGetLengthOfOccupy(ptypeQueueHandle)) < 1)
        return 0;

    /* 限制读取长度 */
    iLength = iLength > iLengthLimit ? iLengthLimit : iLength;

    /* 从队列内获取数据 */
    if(enumQueuePopDatas(ptypeQueueHandle, pvDatas, iLength) != queueNormal)
        return 0;

    return iLength;
}

int32_t iCanxReceiveLengthGet(uint32_t can_periph)
{
    QueueType *ptypeQueueHandle = NULL;

    switch(can_periph)
    {
        case CAN0: ptypeQueueHandle = &g_TypeQueueCan0Read; break;
        case CAN1: ptypeQueueHandle = &g_TypeQueueCan1Read; break;

        default : printf("iCanxReceiveLengthGet channel error.\r\n"); return 0;
    }

    /* 读取队列内有效数据的长度 */
    return iQueueGetLengthOfOccupy(ptypeQueueHandle);
}

int8_t cCanxReceiveClear(uint32_t can_periph)
{
    QueueType *ptypeQueueHandle = NULL;

    switch(can_periph)
    {
        case CAN0: ptypeQueueHandle = &g_TypeQueueCan0Read; break;
        case CAN1: ptypeQueueHandle = &g_TypeQueueCan1Read; break;

        default : printf("cCanxReceiveClear channel error.\r\n"); return 1;
    }

    /* 设置队列状态为空 */
    return enumQueueSetState(ptypeQueueHandle, queueEmpty);
}
